package com.runa.rccprotocol.analysis;

import com.runa.monitor.comm.dto.newComm.AffiliatePanelVO;
import com.runa.monitor.comm.dto.newComm.HotMeterVO;
import com.runa.monitor.comm.dto.newComm.PanelVO;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.monitor.comm.entity.CommPanel;
import com.runa.persistence.RepositoryServicePersis;
import com.runa.protocol.analysis.DtuCMBufferAnalysis;
import com.runa.protocol.analysis.MetaBufferAnalysis;
import com.runa.protocol.dto.IInterData;
import com.runa.protocol.enums.ByteOrder;
import com.runa.protocol.util.ByteUtil;
import com.runa.protocol.util.DigitalUtil;
import com.runa.rccprotocol.dto.equdata.HeatMeterData;
import com.runa.rccprotocol.dto.equdata.PublicBuildingsOrUnitValveData;
import com.runa.rccprotocol.dto.equdata.TerminalCalendarClock;
import com.runa.rccprotocol.dto.equdata.ValveData;
import com.runa.rccprotocol.dto.runa.RunaConcenAffirmDeny;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

@Slf4j
public class HiwitsDeviceAnalysis extends MetaBufferAnalysis<byte[]> {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

    private SimpleDateFormat sdf2 = new SimpleDateFormat("yyMMddHHmmss");

    private String netEquNo;

    @Override
    public int fill(byte[] data, int size, String netEquNo) {
        this.netEquNo = netEquNo;
        int begin;
        for (begin = 0; begin < size; begin++) {
            if ((data[begin] & 0xff) == 0x68) {
                break;
            }
        }
        if (size < begin + 11) return -1;
        int idx = begin + 1;
        int deviceType = data[idx++] & 0xff;
        switch (deviceType) {
            case 0x20:
                String addr = ByteUtil.byteToHexStringFlip(data, idx, 4);
                idx += 7;
                int ctrl = data[idx++] & 0xff;
                int len = data[idx++] & 0xff;
                if (size < begin + len + 13) return -1;
                if (ctrl == 0x81) {
                    if (data[begin + len + 11] == ByteUtil.sum(data, begin, len + 11)) {
                        idx += 3 + 5;
                        HotMeterVO meterData = new HotMeterVO();
                        meterData.setMeterSerial(addr);
                        float heat = (float) (ByteUtil.bcdToInt(data, idx, 4, false) * 0.01);
                        idx += 4;
                        meterData.setAccHeat(RunaDeviceAnalysis.toKwh(heat, data[idx++] & 0xff));
                        float power = (float) (ByteUtil.bcdToInt(data, idx, 4, false) * 0.01);
                        idx += 4;
                        meterData.setPower(RunaDeviceAnalysis.toKw(power, data[idx++] & 0xff));
                        float flow = (float) (ByteUtil.bcdToInt(data, idx, 4, false) * 0.0001);
                        idx += 4;
                        meterData.setFlow(RunaDeviceAnalysis.toM3h(flow, data[idx++] & 0xff));
                        float accFlow = (float) (ByteUtil.bcdToInt(data, idx, 4, false) * 0.01);
                        idx += 4;
                        meterData.setAccFlow(RunaDeviceAnalysis.toM3(accFlow, data[idx++] & 0xff));
                        meterData.setSupplyTemp((float) (ByteUtil.bcdToInt(data, idx, 3, false) * 0.01));
                        idx += 3;
                        meterData.setReturnTemp((float) (ByteUtil.bcdToInt(data, idx, 3, false) * 0.01));
                        idx += 3;
                        meterData.setWorkTime(ByteUtil.bcdToInt(data, idx, 3, false));
                        idx += 3;
                        try {
                            meterData.setMeterDate(TerminalCalendarClock.getInstance(sdf.parse(ByteUtil.bcd2str(data, idx, 7, false))).toDate());
                        } catch (ParseException e) {
                            
                        }
                        idx += 7;
                        meterData.setStatus(ByteUtil.byteToHexString(data, idx, 2));
                        meterData.setFaultCode(TianGangAnalysis.heatMeterFaults(ByteUtil.byteToHexString(data, idx, 2)));
                        RunaConcenResponseData responseData = new RunaConcenResponseData();
                        responseData.addRepData(meterData);
                        this.responseData = responseData;
                    }
                }
                return size - begin - 13 - len;
            case 0x42:
                addr = ByteUtil.bcd2str(data, idx, 4, false);
                idx += 7;
                ctrl = data[idx++] & 0xff;
                len = data[idx++] & 0xff;
                if (size < begin + len + 13) return -1;
                if (ctrl == 0x81) {
                    if (data[begin + len + 11] == ByteUtil.sum(data, begin, len + 11)) {
                        int di = ByteUtil.byteToUShort(data, idx, ByteOrder.AB);
                        idx += 2;
                        if (di == 0x1f90 || di == 0x901f) {
                            if (len == 95) {
                                valveV20(data, idx);
                            } else {
                                valveV21(data, idx);
                            }
                        }
                        if (di == 0x9020 || di == 0x2090) {
                            int serial = data[idx++];
                            ValveVO valveData = new ValveVO();
                            valveData.setValveSerial(addr);
                            valveData.setActOpen((float) (data[idx++] & 0xff));
                            valveData.setSupplyTemp((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 100));
                            idx += 2;
                            valveData.setReturnTemp((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 100));
                            idx += 2;
                            int strategy = 0;
                            if (data[idx] == 0) strategy = 1;
                            if (data[idx] == 6) strategy = 5;
                            valveData.setModel(ValveVO.geneModel(strategy));
                            idx += 3;
                            try {
                                valveData.setValveDate(sdf2.parse(data[idx] + "" + data[idx + 1] + data[idx + 2] + data[idx + 3] + data[idx + 4] + data[idx + 5]));
                            } catch (ParseException e) {
                                
                            }
                            idx += 8;
                            valveData.setStatus(ByteUtil.byteToHexString(data, idx, 2));
                            short status = ByteUtil.byteToShort(data, idx, ByteOrder.BA);
                            ArrayList<String> list = new ArrayList<>();
//                            String faults = "";
                            if ((status & 1) == 1) {
                                list.add("阀门异常");
//                                faults += "阀门异常,";
                            }
                            if ((status >> 2 & 1) == 1) {
                                list.add("进水故障");
//                                faults += "进水故障,";
                            }
                            if ((status >> 3 & 1) == 1) {
                                list.add("回水故障");
//                                faults += "回水故障";
                            }
                            valveData.setFaultCode(list);
//                            valveData.setValveComm(true);
                            RunaConcenResponseData responseData = new RunaConcenResponseData();
                            responseData.addRepData(valveData);
                            this.responseData = responseData;
                        }
                    }
                } else if (ctrl == 0x84) {
                    this.responseData = new RunaConcenAffirmDeny(null, true);
                } else {
                    this.responseData = new RunaConcenAffirmDeny(null, false);
                }
                return size - begin - 13 - len;
            case 0x03://modbus读
                handleModbusMeterData(data, size);
                return 0;
        }
        return 0;
    }

    @SneakyThrows
    private int handleModbusMeterData(byte[] data, int len) {
        int index = 0;
        int serial = data[index] & 0xff;
        String serialNo = String.valueOf(serial);
        int length = serialNo.length();
        StringBuilder serialNoBuf = new StringBuilder(serialNo);
        for (int i = 0; i < 14 - length; i++) {
            serialNoBuf.insert(0, "0");
        }

        HeatMeterData meterData = new HeatMeterData();
        meterData.setSerial(serialNoBuf.toString());

        index += 2;
        int dataLen = data[index] & 0xff;
        int surplus = len - (dataLen + 5);
        if (surplus < 0) {
            return -1;
        }
        ++index;

        //校验
        int checkValue = DigitalUtil.calcCrc16(data, 0, dataLen + 3);
        Integer value = ByteUtil.byteToUShort(data, dataLen + 3, ByteOrder.BA);
        if (checkValue != value) {
            return surplus;
        }
        index += 4;

        double acch = ByteUtil.byteToInt(data, index, ByteOrder.DCBA) * 0.001;
        meterData.setAccHeat((float) acch);
        index += 4;
        double heat = ByteUtil.byteToInt(data, index, ByteOrder.DCBA) * 0.001;
        meterData.setPower((float) heat);
        index += 4;
        double flow = ByteUtil.byteToInt(data, index, ByteOrder.DCBA) * 0.001;
        meterData.setInstantFlow((float) flow);
        index += 4;
        double accFlow = ByteUtil.byteToInt(data, index, ByteOrder.DCBA) * 0.001;
        meterData.setAccFlow((float) accFlow);
        index += 4;
        double inte = ByteUtil.byteToInt(data, index, ByteOrder.BA) * 0.01;
        meterData.setInTemperature((float) inte);
        index += 2;
        double re = ByteUtil.byteToInt(data, index, ByteOrder.BA) * 0.01;
        meterData.setOutTemperature((float) re);
        index += 2;
        int workTime = ByteUtil.byteToInt(data, index, ByteOrder.ABCD);
        meterData.setWorkTime(workTime);
        index += 4;
        String timeS = ByteUtil.bcd2str(data, index, 12, false);
        Date yyyyMMMMddddHHHHmmmmssss = new SimpleDateFormat("yyyyMMMMddddHHHHmmmmssss").parse(timeS);
        index += 12;
        meterData.setMeterDate(TerminalCalendarClock.getInstance(yyyyMMMMddddHHHHmmmmssss));
        meterData.setMeterStatus(heatMeterFaultsOfModbus(ByteUtil.byteToHexString(data, index, 2)));

        RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
        runaConcenResponseData.addRepData(meterData);
        responseData = runaConcenResponseData;
        return surplus;
    }

    private static String heatMeterFaultsOfModbus(String status) {
        int hexCode = Integer.parseInt(status, 16);
        StringBuilder faults = new StringBuilder();
        if ((hexCode >> 10 & 1) == 1) {
            faults.append("电池欠压,");
        }
//        if ((hexCode >> 2 & 1) == 1) {
//            faults.append("进水回水故障,");
//        }
//        if ((hexCode >> 1 & 1) == 1) {
//            faults.append("温度异常,");
//        }
        return faults.toString();
    }


    private void valveV20(byte[] data, int idx) {
        int serial = data[idx++];
        int param = data[idx++];
        String addr = ByteUtil.bcd2str(data, idx, 4, false);
        idx += 7;
        ValveVO valveData = new ValveVO();
        valveData.setValveSerial(addr);
        String panelAddr = ByteUtil.bcd2str(data, idx, 4, false);
        idx += 4;
        int opentime = ByteUtil.byteToUShort(data, idx, ByteOrder.BA);
        idx += 2;
        int closetime = ByteUtil.byteToUShort(data, idx, ByteOrder.BA);
        idx += 2;
        valveData.setOpenDL((float) (data[idx++] & 0xff));
        valveData.setOpenUL((float) (data[idx++] & 0xff));
        valveData.setActOpen((float) (data[idx++] & 0xff));
//        valveData.setValveLockTarget(data[idx++] & 0xff);
        int valveState = ByteUtil.byteToUShort(data, idx, ByteOrder.AB);
        idx += 2;
        int funcSwitch = data[idx++];
        valveData.setOpenLock(data[idx++] == 1);
        int panelState = data[idx++] & 0xff;
        int panelSwitch = data[idx++];
        int panelSignel = data[idx++] & 0xff;
        short faultCode = ByteUtil.byteToShort(data, idx, ByteOrder.AB);
        valveData.setStatus(ByteUtil.byteToHexString(data, idx, 2));
        idx += 2;
        float roomTem = ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10;
//        valveData.setCurrTemperature(ByteUtil.byteToUShort(data, idx, ByteOrder.BA)/10);
        idx += 2;
        valveData.setSupplyTemp((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10));
        idx += 2;
        valveData.setReturnTemp((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10));
        idx += 2;
//        valveData.setCurrApportionPeriodAvgTemperature(ByteUtil.byteToUShort(data, idx, ByteOrder.BA)/10);
        idx += 2;
//        valveData.setSetTemperature(ByteUtil.byteToUShort(data, idx, ByteOrder.BA)/10);
        idx += 2;
        valveData.setTempUL((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10));
        idx += 2;
        valveData.setTempDL((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10));
        idx += 14;
        valveData.setOpenTime((float) ByteUtil.bcdToInt(data, idx, 4, false));
        idx += 4;
//        valveData.setAccHeat(ByteUtil.bcdToInt(data, idx, 4, false));
        idx += 4;
//        valveData.setRecentlyApportionPeriodHeat(ByteUtil.bcdToInt(data, idx, 4, false));
        idx += 31;
        int panelHardVersion = ByteUtil.byteToUShort(data, idx, ByteOrder.BA);

        AffiliatePanelVO panel = new AffiliatePanelVO(0, panelHardVersion, roomTem, faultCode);
        panel.setReadTime(valveData.getReadTime());
        panel.setSerial(addr);
        //温度带面板使用map
//        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
//        stringObjectHashMap.put("valve", valveData);
//        stringObjectHashMap.put("panel", panel);
        try {
            panel.setId(RepositoryServicePersis.getCommPanelByNetIdAndSerial(
                    RepositoryServicePersis.getCommNetEquipmentByNetSerial(this.netEquNo).getId(), valveData.getValveSerial()).getId());
            valveData.getPanelVOList().add(panel);
        } catch (Exception e) {
            log.error("户阀挂面板无面板数据---valveData:{}", valveData, e);
        }
        byte valveFault = (byte) faultCode;
        ArrayList<String> list = new ArrayList<>();
        if ((valveFault & 1) == 1) {
            list.add("无线异常");
        }
        if ((valveFault >> 1 & 1) == 1) {
            list.add("进水故障");
        }
        if ((valveFault >> 2 & 1) == 1) {
            list.add("无线异常");
        }
        valveData.setFaultCode(list);
        valveData.setReadTime(new Date());
        RunaConcenResponseData responseData = new RunaConcenResponseData();
        responseData.addRepData(valveData);
        this.responseData = responseData;
    }

    private void valveV21(byte[] data, int idx) {
        int ser = data[idx++];
        int len = ByteUtil.byteToUShort(data, idx, ByteOrder.AB);
        idx += 2;
        int index = data[idx++];
        String addr = ByteUtil.bcd2str(data, idx, 4, false);
        idx += 7;
        ValveVO valveVO = new ValveVO();
//        ValveData valveData = new ValveData();
        valveVO.setValveSerial(addr);
        String panelAddr = ByteUtil.bcd2str(data, idx, 4, false);
        idx += 25;
        valveVO.setActOpen((float) ((data[idx++] & 0xf) * 10));
        valveVO.setOpenLock((data[idx] >> 3 & 1) == 1);
//        valveVO.setSwitchState((data[idx] >> 4 & 1) == 1);
        idx += 2;
        valveVO.setRemoteSet(valveVO.getActOpen());
//        valveData.setTemperatureLockTarget(ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10);
        idx += 2;
//        valveData.setCurrTemperature(ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10);
        idx += 4;
        valveVO.setTempUL((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10));
        idx += 2;
        valveVO.setTempDL((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10));
        idx += 8;
        float temp = ByteUtil.byteToUShort(data, idx, ByteOrder.BA) / 10;
        idx += 4;
//        valveData.setInTemperature(ByteUtil.byteToUShort(data, idx, ByteOrder.BA)/10);
        idx += 2;
//        valveData.setOutTemperature(ByteUtil.byteToUShort(data, idx, ByteOrder.BA)/10);
        idx += 10;
        valveVO.setOpenTime((float) ByteUtil.bcdToInt(data, idx, 4, false));

        AffiliatePanelVO panelVO = new AffiliatePanelVO(0, 1, temp, (short) 0);
        panelVO.setSerial(valveVO.getValveSerial());
        panelVO.setReadTime(valveVO.getReadTime());
//        ValveData.Panel panel = new ValveVO().Panel(0, 1, temp, (short) 0);
//        valveData.setPanel0(panel);
//        valveData.setReadTime(new Date());
        RunaConcenResponseData responseData = new RunaConcenResponseData();
//        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
//        stringObjectHashMap.put("valve",valveVO);
//        stringObjectHashMap.put("panel",panelVO);
//        panelVO.setId(RepositoryServicePersis.getCommPanelByNetIdAndSerial(
//                RepositoryServicePersis.getCommNetEquipmentByNetSerial(netEquNo).getId(),valveVO.getValveSerial()).getId());
        try {
            String netId = RepositoryServicePersis.getCommNetEquipmentByNetSerial(this.netEquNo).getId();
            panelVO.setId(RepositoryServicePersis.getCommPanelByNetIdAndSerial(
                    netId, valveVO.getValveSerial()).getId());
            valveVO.getPanelVOList().add(panelVO);
        } catch (Exception e) {
            log.error("海威茨户阀挂面板无面板数据---valveData:{}", valveVO);
        }

        valveVO.getPanelVOList().add(panelVO);
        responseData.addRepData(valveVO);
//        responseData.addRepData(valveData);
        this.responseData = responseData;
    }

    public static void main(String[] args) {
//        HiwitsDeviceAnalysis analysis = new HiwitsDeviceAnalysis();
//        DtuCMBufferAnalysis cmBufferAnalysis = new DtuCMBufferAnalysis(analysis, 1);
//        byte[] bytes = ByteUtil.hexStringToByte("78 56 34 12 31 30 37 31 30 30 30 30 31 32 37 00 C0 A8 01 4D 1F");
////        cmBufferAnalysis.fill(bytes, bytes.length);
////        bytes = ByteUtil.hexStringToByte("6842201415100055558155901F0100501320141510005555FFFFFFFF000080000000000000000080000001FF1F210041A0AA5941FA00FA0000005E0132000A002800FFFFC800C800FFFFFFFF10100420050550200152010015261626A5250830C616");
//        bytes = ByteUtil.hexStringToByte("F8 00 00 0E 00 81 47 74 04 00 48 00 00 00 00 00 02 00 90 16");
//        analysis.fill(bytes, bytes.length);
//        IInterData data = cmBufferAnalysis.gain();
//        System.out.println(data);

        byte[] bytes = ByteUtil.hexStringToByte("0400");
        String s = heatMeterFaultsOfModbus(ByteUtil.byteToHexString(bytes, 0, 2));
        System.out.println(s);

    }

}
